/*
 * Demo application for DMA buffer sharing between V4L2 and DRM
 * Tomasz Stanislawski <t.stanisl...@samsung.com>
 *
 * Copyright 2012 Samsung Electronics Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

#include <errno.h>
#include <fcntl.h>
#include <math.h>
#include <poll.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>

//#include <drm/drm.h>
//#include <drm/drm_mode.h>
#include <libdrm/drm.h>
#include <libdrm/drm_mode.h>

#include <linux/videodev2.h>

#include <xf86drm.h>
#include <xf86drmMode.h>

#define JPG "./image%d.jpg"

#define ERRSTR strerror(errno)

#define BYE_ON(cond, ...) \
do { \
	if (cond) { \
		int errsv = errno; \
		fprintf(stderr, "ERROR(%s:%d) : ", \
			__FILE__, __LINE__); \
		errno = errsv; \
		fprintf(stderr,  __VA_ARGS__); \
		abort(); \
	} \
} while(0)
#define PRINTF printf

static inline int warn(const char *file, int line, const char *fmt, ...)
{
	int errsv = errno;
	va_list va;
	va_start(va, fmt);
	fprintf(stderr, "WARN(%s:%d): ", file, line);
	vfprintf(stderr, fmt, va);
	va_end(va);
	errno = errsv;
	return 1;
}

#define WARN_ON(cond, ...) \
	((cond) ? warn(__FILE__, __LINE__, __VA_ARGS__) : 0)

struct setup {
	char module[32];
	int conId;
	uint32_t crtId;
	int crtIdx;
	uint32_t planeId;
	char modestr[32];
	char video[32];
	unsigned int w, h, bpp, pitch;
	unsigned int use_wh : 1;
	unsigned int in_fourcc;
	unsigned int out_fourcc;
	unsigned int buffer_count;
	unsigned int use_crop : 1;
	unsigned int use_compose : 1;
	struct v4l2_rect crop;
	struct v4l2_rect compose;
};

struct buffer {
	unsigned int bo_handle;
	unsigned int fb_handle;
	int dbuf_fd;
};

struct stream {
	int v4lfd;
	int current_buffer;
	int buffer_count;
	struct buffer *buffer;
} stream;

static void usage(char *name)
{
	fprintf(stderr, "usage: %s [-Moisth]\n", name);
	fprintf(stderr, "\t-M <drm-module>\tset DRM module\n");
	fprintf(stderr, "\t-o <connector_id>:<crtc_id>:<mode>\tset a mode\n");
	fprintf(stderr, "\t-i <video-node>\tset video node like /dev/video*\n");
	fprintf(stderr, "\t-S <width,height>\tset input resolution\n");
	fprintf(stderr, "\t-f <fourcc>\tset input format using 4cc\n");
	fprintf(stderr, "\t-F <fourcc>\tset output format using 4cc\n");
	fprintf(stderr, "\t-s <width,height>@<left,top>\tset crop area\n");
	fprintf(stderr, "\t-t <width,height>@<left,top>\tset compose area\n");
	fprintf(stderr, "\t-b buffer_count\tset number of buffers\n");
	fprintf(stderr, "\t-h\tshow this help\n");
	fprintf(stderr, "\n\tDefault is to dump all info.\n");
}

static inline int parse_rect(char *s, struct v4l2_rect *r)
{
	return sscanf(s, "%d,%d@%d,%d", &r->width, &r->height,
		&r->top, &r->left) != 4;
}

static int parse_args(int argc, char *argv[], struct setup *s)
{
	if (argc <= 1)
		usage(argv[0]);

	int c, ret;
	memset(s, 0, sizeof(*s));

	while ((c = getopt(argc, argv, "M:o:i:S:f:F:s:t:b:h")) != -1) {
		switch (c) {
		case 'M':
			strncpy(s->module, optarg, 31);
			break;
		case 'o':
			ret = sscanf(optarg, "%u:%u:%31s", &s->conId, &s->crtId,
				s->modestr);
			if (WARN_ON(ret != 3, "incorrect mode description\n"))
				return -1;
			break;
		case 'i':
			strncpy(s->video, optarg, 31);
			break;
		case 'S':
			ret = sscanf(optarg, "%u,%u", &s->w, &s->h);
			if (WARN_ON(ret != 2, "incorrect input size\n"))
				return -1;
			s->use_wh = 1;
			break;
		case 'f':
			if (WARN_ON(strlen(optarg) != 4, "invalid fourcc\n"))
				return -1;
			s->in_fourcc = ((unsigned)optarg[0] << 0) |
				((unsigned)optarg[1] << 8) |
				((unsigned)optarg[2] << 16) |
				((unsigned)optarg[3] << 24);
			break;
		case 'F':
			if (WARN_ON(strlen(optarg) != 4, "invalid fourcc\n"))
				return -1;
			s->out_fourcc = ((unsigned)optarg[0] << 0) |
				((unsigned)optarg[1] << 8) |
				((unsigned)optarg[2] << 16) |
				((unsigned)optarg[3] << 24);
			break;
		case 's':
			ret = parse_rect(optarg, &s->crop);
			if (WARN_ON(ret, "incorrect crop area\n"))
				return -1;
			s->use_crop = 1;
			break;
		case 't':
			ret = parse_rect(optarg, &s->compose);
			if (WARN_ON(ret, "incorrect compose area\n"))
				return -1;
			s->use_compose = 1;
			break;
		case 'b':
			ret = sscanf(optarg, "%u", &s->buffer_count);
			if (WARN_ON(ret != 1, "incorrect buffer count\n"))
				return -1;
			break;
		case '?':
		case 'h':
			usage(argv[0]);
			return -1;
		}
	}

	return 0;
}

static int buffer_create(struct buffer *b, int drmfd, struct setup *s,
	uint64_t size, uint32_t pitch)
{
	struct drm_mode_create_dumb gem;
	struct drm_mode_destroy_dumb gem_destroy;
	int ret;

	memset(&gem, 0, sizeof gem);
	gem.width = s->w;
	gem.height = s->h;
	gem.bpp = 32;//virtio_gpu driver will check bpp=32?
	gem.size = size;

	ret = ioctl(drmfd, DRM_IOCTL_MODE_CREATE_DUMB, &gem);
	if (WARN_ON(ret, "CREATE_DUMB failed: %s\n", ERRSTR))
		return -1;
	/*gem.size should = size*/
	printf("bo %u %ux%u bpp %u size %lu (%lu)\n", 
					gem.handle,
					gem.width, 
					gem.height,
					gem.bpp,
					(long)gem.size,
					(long)size);

	b->bo_handle = gem.handle;

	struct drm_prime_handle prime;
	memset(&prime, 0, sizeof prime);
	prime.handle = b->bo_handle;

	ret = ioctl(drmfd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &prime);
	if (WARN_ON(ret, "PRIME_HANDLE_TO_FD failed: %s\n", ERRSTR))
		goto fail_gem;
	printf("dbuf_fd = %d\n", prime.fd);
	b->dbuf_fd = prime.fd;

	uint32_t offsets[4] = { 0 };
	uint32_t pitches[4] = { pitch };
	uint32_t bo_handles[4] = { b->bo_handle };
	unsigned int fourcc = s->out_fourcc;
	if (!fourcc)
		fourcc = s->in_fourcc;

	fprintf(stderr, "FB fourcc %c%c%c%c\n",
		fourcc,
		fourcc >> 8,
		fourcc >> 16,
		fourcc >> 24);

/*
extern int drmModeAddFB2(int fd, uint32_t width, uint32_t height,
			 uint32_t pixel_format, const uint32_t bo_handles[4],
			 const uint32_t pitches[4], const uint32_t offsets[4],
			 uint32_t *buf_id, uint32_t flags);
*/
	/*using s->w,s->h as buffers w,h
	* and the buffer id is b->fb_handle
	*/
	ret = drmModeAddFB2(drmfd, s->w, s->h, fourcc, bo_handles,
		pitches, offsets, &b->fb_handle, 0);
	if (WARN_ON(ret, "drmModeAddFB2 failed: %s\n", ERRSTR))
		goto fail_prime;

	return 0;

fail_prime:
	close(b->dbuf_fd);

fail_gem:
	memset(&gem_destroy, 0, sizeof gem_destroy);
	gem_destroy.handle = b->bo_handle,
	ret = ioctl(drmfd, DRM_IOCTL_MODE_DESTROY_DUMB, &gem_destroy);
	WARN_ON(ret, "DESTROY_DUMB failed: %s\n", ERRSTR);

	return -1;
}

static int find_mode(drmModeModeInfo *m, int drmfd, struct setup *s,
	uint32_t *con)
{
	int ret = -1;
	int i;

	drmModeRes *res = drmModeGetResources(drmfd);
	printf("ctrc num:%d,conn num:%d\r\n",res->count_crtcs,res->count_connectors);

	if (WARN_ON(!res, "drmModeGetResources failed: %s\n", ERRSTR))
		return -1;

	if (WARN_ON(res->count_crtcs <= 0, "drm: no crts\n"))
		goto fail_res;

	if (WARN_ON(res->count_connectors <= 0, "drm: no connectors\n"))
		goto fail_res;

	s->crtIdx = res->crtcs[0];
	s->conId = res->connectors[0];
	printf("ctrc id:%d,conn id:%d\r\n",s->crtIdx,s->conId);

	drmModeConnector *c;
	c = drmModeGetConnector(drmfd, s->conId);
	if (WARN_ON(!c, "drmModeGetConnector failed: %s\n", ERRSTR))
		goto fail_res;

	if (WARN_ON(!c->count_modes, "connector supports no mode\n"))
		goto fail_conn;
	
	if(s->modestr[0]=='\0')
	{
		strcpy(s->modestr,"1920x1080");
		printf("using default connector mode: %s\r\n",s->modestr);
	}

	drmModeModeInfo *found = NULL;
	for (int i = 0; i < c->count_modes; ++i)
		if (strcmp(c->modes[i].name, s->modestr) == 0){
			found = &c->modes[i];
			printf("get mode found:%s@%d\r\n",found->name,found->vrefresh);
		}

	if (WARN_ON(!found, "mode %s not supported\n", s->modestr)) {
		fprintf(stderr, "Valid modes:");
		for (int i = 0; i < c->count_modes; ++i){
			fprintf(stderr, " %s", c->modes[i].name);
			fprintf(stderr, "\n");
		}
		goto fail_conn;
	}

	memcpy(m, found, sizeof *found);
	if (con)
		*con = c->connector_id;
	ret = 0;

fail_conn:
	drmModeFreeConnector(c);

fail_res:
	drmModeFreeResources(res);

	return ret;
}

static int find_plane(int drmfd, struct setup *s)
{
	drmModePlaneResPtr planes;
	drmModePlanePtr plane;
	unsigned int i;
	unsigned int j;
	int ret = 0;

	drmSetClientCap(drmfd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);//set capability
	planes = drmModeGetPlaneResources(drmfd);
	if (WARN_ON(!planes, "drmModeGetPlaneResources failed: %s\n", ERRSTR))
		return -1;
	
	printf("get planes:%d\r\n",planes->count_planes);

	plane = drmModeGetPlane(drmfd, planes->planes[0]);
	if (WARN_ON(!planes, "drmModeGetPlane failed: %s\n", ERRSTR))
		goto fail_plane;

	printf("plane id:%d,crtc id:%d,formats:%s\r\n",
			plane->plane_id,plane->crtc_id,&plane->formats[0]);

	s->planeId = plane->plane_id;
	printf("s->plane ID:%d\r\n",s->planeId);

fail_plane:
	drmModeFreePlane(plane);

faile_res:
	drmModeFreePlaneResources(planes);

	return ret;
}

static void process_image(const void *p, int size)
{
    FILE *fp;
    static int num = 0;
    char image_name[20];

    sprintf(image_name, JPG, num++);
    printf("image_name = %s\n", image_name);
    if((fp = fopen(image_name, "w+")) == NULL){
        perror("Fail to fopen");
        exit(EXIT_FAILURE);
    }
    fwrite(p, size, 1, fp);
    //usleep(500);
    fclose(fp);
    printf(".....\n");

}

void cap2s(__u32 capabilities)
{
    if (capabilities & V4L2_CAP_VIDEO_CAPTURE)
        printf("        Video Capture\n");
    if (capabilities & V4L2_CAP_VIDEO_OUTPUT)
        printf("        Video Output\n");
    if (capabilities & V4L2_CAP_VIDEO_OVERLAY)
        printf("        Video Overly\n");
    if (capabilities & V4L2_CAP_VBI_CAPTURE)
        printf("        VBI Capture\n");
    if (capabilities & V4L2_CAP_VBI_OUTPUT)
        printf("        VBI Output\n");
    if (capabilities & V4L2_CAP_SLICED_VBI_CAPTURE)
        printf("        Sliced VBI Capture\n");
    if (capabilities & V4L2_CAP_SLICED_VBI_OUTPUT)
        printf("        Sliced VBI Output\n");
    if (capabilities & V4L2_CAP_RDS_CAPTURE)
        printf("        RDS Capture\n");
    if (capabilities & V4L2_CAP_VIDEO_OUTPUT_OVERLAY)
        printf("        Video Output Overlay\n");
    if (capabilities & V4L2_CAP_HW_FREQ_SEEK)
        printf("        HW Frequency Seek\n");
    if (capabilities & V4L2_CAP_RDS_OUTPUT)
        printf("        RDS Output\n");

    if (capabilities & V4L2_CAP_VIDEO_CAPTURE_MPLANE)
        printf("        Video Capture Mplane\n");
    if (capabilities & V4L2_CAP_VIDEO_OUTPUT_MPLANE)
        printf("        Video Output Mplane\n");
    if (capabilities & V4L2_CAP_VIDEO_M2M_MPLANE)
        printf("        M2M Mplane Device\n");
    if (capabilities & V4L2_CAP_VIDEO_M2M)
        printf("        M2M Device\n");
    if (capabilities & V4L2_CAP_TUNER)
        printf("        Tuner\n");
    if (capabilities & V4L2_CAP_AUDIO)
        printf("        Audio\n");
    if (capabilities & V4L2_CAP_RADIO)
        printf("        Radio\n");
    if (capabilities & V4L2_CAP_MODULATOR)
        printf("        Modulator\n");

    if (capabilities & V4L2_CAP_SDR_CAPTURE)
        printf("        SDR Capture\n");
    if (capabilities & V4L2_CAP_EXT_PIX_FORMAT)
        printf("        Extended Pix Format\n");
    if (capabilities & V4L2_CAP_SDR_OUTPUT)
        printf("        SDR Output\n");
    if (capabilities & V4L2_CAP_META_CAPTURE)
        printf("        Metadata Capture\n");
    if (capabilities & V4L2_CAP_READWRITE)
        printf("        Read / Write\n");
    if (capabilities & V4L2_CAP_ASYNCIO)
        printf("        Async I/O\n");
    if (capabilities & V4L2_CAP_STREAMING)
        printf("        Streaming\n");
    if (capabilities & V4L2_CAP_META_OUTPUT)
        printf("        Metadata Output\n");
    if (capabilities & V4L2_CAP_TOUCH)
        printf("        Touch Device\n");
    if (capabilities & V4L2_CAP_IO_MC)
        printf("        I/O Media Controller\n");
    if (capabilities & V4L2_CAP_DEVICE_CAPS)
        printf("        Device Capabilities\n");
    printf("\n");
}


void get_capabilities(struct v4l2_capability cap)
{
    printf("------- VIDIOC_QUERYCAP ----\n");
    printf("  driver: %s\n", cap.driver);
    printf("  card: %s\n", cap.card);
    printf("  bus_info: %s\n", cap.bus_info);
    printf("  version: %d.%d.%d\n",
           (cap.version >> 16) & 0xff,
           (cap.version >> 8) & 0xff,
           (cap.version & 0xff));
    printf("  capabilities: %08X\n", cap.capabilities);
    cap2s(cap.capabilities);

    if (cap.capabilities & V4L2_CAP_DEVICE_CAPS) {
		printf("\tDevice Caps      : 0x%08x\n", cap.device_caps);
        cap2s(cap.device_caps);
    }

    return;
}

int main(int argc, char *argv[])
{
	int ret;
	struct setup s;
	drmModeRes *res;
	drmModeConnector *conn;
	drmModePlaneRes *plane_res;
	uint32_t conn_id,crtc_id;

	ret = parse_args(argc, argv, &s);
	BYE_ON(ret, "failed to parse arguments\n");
	BYE_ON(s.module[0] == 0, "DRM module is missing\n");
	BYE_ON(s.video[0] == 0, "video node is missing\n");
	BYE_ON((s.in_fourcc == 0)&&(s.out_fourcc == 0), "no 4cc specified,at least one\n");

	int drmfd = drmOpen(s.module, NULL);
	BYE_ON(drmfd < 0, "drmOpen(%s) failed: %s\n", s.module, ERRSTR);

	int v4lfd = open(s.video, O_RDWR);
	BYE_ON(v4lfd < 0, "failed to open %s: %s\n", s.video, ERRSTR);

	struct v4l2_capability caps;
	memset(&caps, 0, sizeof caps);

	ret = ioctl(v4lfd, VIDIOC_QUERYCAP, &caps);
	BYE_ON(ret, "VIDIOC_QUERYCAP failed: %s\n", ERRSTR);
	//get_capabilities(caps);
	/* TODO: add single plane support */
	BYE_ON(~caps.capabilities & V4L2_CAP_VIDEO_CAPTURE,
		"video: singleplanar capture is not supported\n");

	struct v4l2_format fmt;
	memset(&fmt, 0, sizeof fmt);
	fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

	ret = ioctl(v4lfd, VIDIOC_G_FMT, &fmt);
	BYE_ON(ret < 0, "VIDIOC_G_FMT failed: %s\n", ERRSTR);
	printf("G_FMT(start): width = %u, height = %u, size = %u, pitch = %u ,4cc = %.4s\n",
		fmt.fmt.pix.width,
		fmt.fmt.pix.height,
		fmt.fmt.pix.sizeimage,
		fmt.fmt.pix.bytesperline,
		(char*)&fmt.fmt.pix.pixelformat);

	if (s.use_wh) {
		fmt.fmt.pix.width = s.w;
		fmt.fmt.pix.height = s.h;
		fmt.fmt.pix.bytesperline = 4*s.w;
		printf("use w=%d,h=%d,pitch=%d\r\n",
						fmt.fmt.pix.width,
						fmt.fmt.pix.height,
						fmt.fmt.pix.bytesperline);
	}
	if (s.in_fourcc){
		fmt.fmt.pix.pixelformat = s.in_fourcc;
	}

	ret = ioctl(v4lfd, VIDIOC_S_FMT, &fmt);
	BYE_ON(ret < 0, "VIDIOC_S_FMT failed: %s\n", ERRSTR);

	ret = ioctl(v4lfd, VIDIOC_G_FMT, &fmt);
	BYE_ON(ret < 0, "VIDIOC_G_FMT failed: %s\n", ERRSTR);
	printf("G_FMT(final): width = %u, height = %u, size = %u, pitch = %u ,4cc = %.4s\n",
		fmt.fmt.pix.width,
		fmt.fmt.pix.height,
		fmt.fmt.pix.sizeimage,
		fmt.fmt.pix.bytesperline,
		(char*)&fmt.fmt.pix.pixelformat);

	struct v4l2_requestbuffers rqbufs;
	memset(&rqbufs, 0, sizeof(rqbufs));
	if(s.buffer_count){
		rqbufs.count = s.buffer_count;
	}else{
		s.buffer_count = 2;
		rqbufs.count = 2;
	}
	rqbufs.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
	rqbufs.memory = V4L2_MEMORY_DMABUF;

	ret = ioctl(v4lfd, VIDIOC_REQBUFS, &rqbufs);
	BYE_ON(ret < 0, "VIDIOC_REQBUFS failed: %s\n", ERRSTR);
	BYE_ON(rqbufs.count < s.buffer_count, "video node allocated only "
		"%u of %u buffers\n", rqbufs.count, s.buffer_count);
	printf("VIDIOC_REQBUFS succeed!\n\n");
/*
	s.in_fourcc = fmt.fmt.pix.pixelformat;
	s.w = fmt.fmt.pix.width;
	s.h = fmt.fmt.pix.height;
*/
	/* TODO: add support for multiplanar formats */
	struct buffer buffer[s.buffer_count];
	uint32_t size = fmt.fmt.pix.sizeimage;
	uint32_t pitch = fmt.fmt.pix.bytesperline;
	printf("size = %u pitch = %u\n", size, pitch);
	for (unsigned int i = 0; i < s.buffer_count; ++i) {
		ret = buffer_create(&buffer[i], drmfd, &s, size, pitch);
		BYE_ON(ret, "failed to create buffer%d\n", i);
	}
	printf("%d buffers ready\n",s.buffer_count);

	drmModeModeInfo drmmode;
	uint32_t con;
	ret = find_mode(&drmmode, drmfd, &s, &con);
	BYE_ON(ret, "failed to find valid mode\n");

	ret = find_plane(drmfd, &s);
	BYE_ON(ret, "failed to find compatible plane\n");

	/*------start qbuf-----*/
	for (unsigned int i = 0; i < s.buffer_count; ++i) {
		struct v4l2_buffer buf;
		memset(&buf, 0, sizeof buf);

		buf.index = i;
		buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
		buf.memory = V4L2_MEMORY_DMABUF;
		buf.m.fd = buffer[i].dbuf_fd;
		ret = ioctl(v4lfd, VIDIOC_QBUF, &buf);
		BYE_ON(ret < 0, "VIDIOC_QBUF for buffer %d failed: %s (fd %u)\n",
			buf.index, ERRSTR, buffer[i].dbuf_fd);
	}
	/*------end qbuf-----*/

	/*-----start stream on-----*/
	int type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
	ret = ioctl(v4lfd, VIDIOC_STREAMON, &type);
	BYE_ON(ret < 0, "STREAMON failed: %s\n", ERRSTR);
	/*-----end stream on-----*/

	struct pollfd fds[] = {
		{ .fd = v4lfd, .events = POLLIN },
		{ .fd = drmfd, .events = POLLIN },
	};

	/* buffer currently used by drm */
	stream.v4lfd = v4lfd;
	stream.current_buffer = -1;
	stream.buffer = buffer;

	if (!s.use_compose) {
		s.compose.left = 0;
		s.compose.top = 0;
		s.compose.width = fmt.fmt.pix.width;
		s.compose.height = fmt.fmt.pix.height;
	}

	while ((ret = poll(fds, 2, 5000)) > 0) {
		struct v4l2_buffer buf;

		/* dequeue buffer */
		memset(&buf, 0, sizeof buf);
		buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
		buf.memory = V4L2_MEMORY_DMABUF;
		ret = ioctl(v4lfd, VIDIOC_DQBUF, &buf);
		BYE_ON(ret, "VIDIOC_DQBUF failed: %s\n", ERRSTR);

		printf("set:left=%d,top=%d,width=%d,height=%d,s.w=%d,s.h=%d\r\n",
				s.compose.left,
				s.compose.top,
				s.compose.width,
				s.compose.height,
				s.w,
				s.h);

#define use_set_crtc

#ifdef use_set_plane
	/*./dmabuf-sharing -M virtio_gpu -i /dev/video0 -S 1920,1080 -f XR24 -F XR24 -b 2 -o 34:33:1920x1080*/
		ret = drmModeSetPlane(drmfd, s.planeId, s.crtId,
				      buffer[buf.index].fb_handle, 0,
				      s.compose.left, s.compose.top,
				      s.compose.width,
				      s.compose.height,
				      0, 0, s.w << 16, s.h << 16);
		BYE_ON(ret, "drmModeSetPlane failed: %s\n", ERRSTR);

		printf("drmModeSetPlane\r\n");
#endif

#ifdef use_set_crtc
		/*./dmabuf-sharing -M virtio_gpu -i /dev/video0 -S 1920,1080 -F XR24 -b 2*/
		res = drmModeGetResources(drmfd);
		BYE_ON(!res, "drmModeGetResourcesfailed");
		crtc_id = res->crtcs[0];
		conn_id = res->connectors[0];
		//printf("--crtc id:%d,connector id:%d--\r\n",crtc_id,conn_id);

		conn = drmModeGetConnector(drmfd, conn_id);
		drmModeSetCrtc(drmfd, crtc_id, buffer[buf.index].fb_handle,
			0, 0, &conn_id, 1, &drmmode);

		printf("drmModeSetCrtc\r\n");
#endif
		if (stream.current_buffer != -1) {
			memset(&buf, 0, sizeof buf);
			buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
			buf.memory = V4L2_MEMORY_DMABUF;
			buf.index = stream.current_buffer;
			buf.m.fd = stream.buffer[stream.current_buffer].dbuf_fd;

			ret = ioctl(stream.v4lfd, VIDIOC_QBUF, &buf);
			BYE_ON(ret, "VIDIOC_QBUF(index = %d) failed: %s\n",
			       stream.current_buffer, ERRSTR);
		}

		stream.current_buffer = buf.index;
	}

	return 0;
}

